/* Copyright 2014 Jan Wolter */

#include "stack.h"
#include "tableau.h"
#include "found.h"
#include "stock.h"
#include "solve.h"
#include "game.h"

char *gamename= "Kiev";
char *gameopt= "TSD";
Stack *gathered= NULL;
Stack *temp= NULL;

int nplayed= 0;
int nwon= 0;
int cardsleft= 0;
int maxoff;

int peroddtableau= 4;
int pereventableau= 4;
int maywrap= 0;

void setopt(char c)
{
    switch (c)
    {
	case 'T': /* Play "Kev" */
	    /* Drop through */
	    peroddtableau= 3;
	case 'S': /* Play "Sevastopol" */
	    pereventableau= 3;
	    break;
	case 'D': /* Play "Dnieper" */
	    maywrap= 1;
	    break;
    }
}

/* This is the main program for setting up the current game */
void exec(int gather, int arif, int over, int cut)
{
    /* Could set things like ndeck, nsuit here */

    /* Build and shuffle the deck */
    Stack *shuf= mixcards(arif, over, cut);

    /* Create the foundations
     *   For complete sequences we MUST use the sf_complete handler */
    superfound= sf_complete;
    for (int s= 0; s < nsuit; s++)
	makeFound(1, s, +1, 13);

    /* Create the tableau */
    for (int i= 1; i <= 7; i++)
	makeTableau(i % 2 ? pereventableau : peroddtableau, FLIP_ALL, shuf,
	    S_SAMESUIT, -1, S_ANYTHING, npip,
	    maywrap ? 0 : 1, F_ANYTHING, BREAK_NOFIT, 0);

    makeStock(DT_TABLEAU,1,1,shuf);

    freeStack(shuf);

    if (verbose > 1) printState(stdout, stacks);

    maxoff= 0;
    int win= solve(gather,0);

    if (verbose > 0) printf("maxoff=%d\n",maxoff);
    nplayed++;
    cardsleft+= maxoff;
    if (win) nwon++;

    cleanFound();
    cleanTableau();
    cleanStock();
    cleanStacks();
    cleanVisited();
}

void gatherAll()
{
    if (gathered == NULL)
	gathered= allocStack(ncard);
    else
	gathered->n= 0;

    gatherFound(gathered);
    gatherTableau(gathered);
    /*gatherStock(gathered); - Stock will always be empty */
    if (gathered->n != ncard)
    {
	printf("Gather Failed - found %d cards\n",gathered->n);
	exit(1);
    }
}

/* How good is a move? Returns 0 if the move is completely safe and should
 * be made immediately without counting this position a a choice point for
 * backtracking. Positive values are lower for better moves. Negative values
 * mean the move should not be done at all.
 */
int rateMove(Stack *src, int index1, int len, Stack *dst)
{
    /* Deals are our least favorite move */
    if (src->type == STOCK) return 50;

    /* Always safe to move a stack to the foundation in Kiev */
    if (dst->type == FOUND) return 0;

    /* Not too found of filling empty spaces */
    if (dst->n == 0) return 20;

    /* Rather fond of creating empty spaces */
    if (index1 == 0) return 1;

    /* Also like turning over new cards */
    if (!src->c[index1-1]->faceup) return 2;

    return 3;
}

void printState(FILE *f, Stack *stks)
{
    printFound(f, stks);
    printTableau(f, stks);
    printStock(f, stks);
}

int victory()
{
    int off= nOff();
    if (off > maxoff) maxoff= off;
    return (off == ncard);
}

/* Return a quality rating for the current solution. Bigger is better. Usually
 * it's just cards off. This is used to decide which solution to report in
 * cases where we never win.
 */
int quality()
{
    return nOff();
}

void summary()
{
    printf("Played:    %d games\n",nplayed);
    printf("Won:       %d games (%.2f%)\n",nwon,(float)nwon*100/nplayed);
    printf("Cards Off: %.2f\n",(float)cardsleft/nplayed);
}

/* Return a string that uniquely describes the current state. */
char *currstate()
{
    /* ncards for all the cards on things, 7 for card list terminators
     */
    char buf[ncard+20], *p= buf;

    /* List of cards on each tableau pile - probably we should normalize
     * the order of tableau piles, sorting them by the first card on them,
     * We add 52 to any facedown card.
     */
    for (int k= 0; k < ntableau; k++)
    {
	Stack *s= stacks + tableau[k].id;
	for (int i= 0; i < s->n; i++)
	    *(p++)= 1 + (s->c[i] - deck) + (s->c[i]->faceup ? ncard : 0);
	*(p++)= 2*ncard + 1; /* The card list terminator */
    }

    *p= '\0';

    return strdup(buf);
}
